#ifndef TEMPLATEPLUGIN_H
#define TEMPLATEPLUGIN_H

#include "SbotPlugin.h"

#include <QObject>
#include <QQmlComponent>
#include <QQmlContext>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QTimer>

#define PLUGIN_NAME    "Teminal"
#define PLUGIN_VERSION "2.5.0"
#define PLUGIN_IID     "org.SBOT.SbotPlugin"
#define PLUGIN_QMLRES  "qrc:/Qml/TeminalPlugin.qml"
#define PLUGIN_LOGO    ":/Res/Icon/TeminalPluginLogo.png"

class MySerialPort
{
  public:
    QSerialPort serialPort;
    QString     portName         = "";
    bool        isSelect         = false;
    bool        isOpen           = false;
    QString     baudRate         = "115200";
    QString     dataBits         = "8";
    QString     stopBits         = "0";
    QString     parityBits       = "无";
    bool        timeStamp        = false;
    bool        rollDisable      = false;
    bool        hexReception     = false;
    bool        hexLineFeed      = false;
    bool        hexSending       = false;
    bool        autoLineFeed     = false;
    bool        isAutoSend       = false;
    QString     autoSendInterval = "1000";
    int         pattern          = 1;

    struct lineData
    {
        QString lineName;
        float   data;
        qint64  timeStamp;
        int     tf;
    };

  private:
    int maxLineNum = 10;

  public:
    QMutex txDataBufferMutex;  // 发送缓冲区互斥锁
    QMutex rxDataBufferMutex;  // 接收缓冲区互斥锁

    QString               txDataBuffer;  // 发送数据缓存区
    QString               rxDataBuffer;  // 接收数据缓存区
    std::vector<lineData> line;          // 曲线数据缓冲区

  public:
    void pushRxData(QString& data)
    {
        if (this->rxDataBuffer.length() > 4096)
        {
            return;
        }
        this->rxDataBufferMutex.lock();
        this->rxDataBuffer += data;
        this->rxDataBufferMutex.unlock();
    }

    QString popRxData()
    {
        this->rxDataBufferMutex.lock();
        int     lastIndex = this->rxDataBuffer.lastIndexOf('\n');
        QString data;
        if (lastIndex != -1)
        {
            data = this->rxDataBuffer.left(lastIndex + 1);
            this->rxDataBuffer.remove(0, lastIndex + 1);
        }
        else
        {
            data = this->rxDataBuffer;
            this->rxDataBuffer.clear();
        }
        this->rxDataBufferMutex.unlock();

        return data;
    }

    void AddLine(QString& lineName)
    {
        qint64 timestampMillis = 0;

        for (auto& lineData : line)
        {
            if (lineData.lineName == lineName)
            {
                return;
            }
        }

        if (line.size() < maxLineNum)
        {
            timestampMillis = QDateTime::currentDateTime().toMSecsSinceEpoch();
            line.push_back({lineName, 0, timestampMillis, 50});
        }
    }

    void pushLineData(lineData& line, float data)
    {
        int    timeInterval    = 0;
        qint64 timestampMillis = 0;
        float  alpha           = 0;

        line.data = data;

        // timestampMillis = QDateTime::currentDateTime().toMSecsSinceEpoch();
        // timeInterval = timestampMillis - line.timeStamp;
        // line.timeStamp = timestampMillis;

        // if (timeInterval > 100) {
        //     line.data = data;
        // }

        // //低通滤波
        // alpha = line.tf / (line.tf + timeInterval);
        // line.data = alpha * line.data + (1.0f - alpha) * data;

        return;
    }
};

class TeminalPlugin : public SbotPlugin
{
    Q_OBJECT

    Q_PLUGIN_METADATA(IID PLUGIN_IID FILE "plugin.json")
    Q_INTERFACES(SbotPlugin)

  public:
    QList<MySerialPort*> serialPort;
    QTimer*              refreshTimer;
    QTimer*              refreshPortTimer;
    int                  timeStamp      = 0;
    int                  refreshTimeOut = 10;

  private:
    void RefreshSerialPort(void);  // 刷新串口
    void RefreshDataToQml();       // 刷新界面

  public:
    explicit TeminalPlugin(QObject* parent = nullptr);
    void             PluginInitAtThreadHook() override;
    int              PluginThreadLoop() override;
    Q_INVOKABLE bool OpenSerialPort(QString portName);
    Q_INVOKABLE void CloseSerialPort(QString portName);
    Q_INVOKABLE void FlushSerialPortCfg(const QVariantMap& config);
    Q_INVOKABLE void SerialPortTx(QString portName, QString text);
    Q_INVOKABLE void AddNewLine(QString portName, QString lineName);
    Q_INVOKABLE void DeleteAllLine(QString portName);

  signals:
    void OpenSerialPortRequested(const QString& portName);
    void SerialPortTxRequested(QString portName, QString text);

  public slots:
    void HandleOpenSerialPort(const QString& portName);
    void HandleSerialPortTx(QString portName, QString text);
};

#endif  // TEMPLATEPLUGIN_H
